/*******************************************************************************
 * File name: 		init.c
 * Description: 
 * Project: 		_framework
 * Target: 			LPC1788
 * Compiler: 		arm-none-eabi-gcc
 * Date: 			Jun 26, 2012
 * Author: 			kuba
 * Based on: 		---
 ******************************************************************************/

/*==============================================================================
 Includes
==============================================================================*/
# include "LPC177x_8x.h"
# include "typedef.h"
# include "hdr_sc.h"
# include "gpio.h"
# include "init.h"

/*==============================================================================
 Defines
==============================================================================*/
#define CRYSTAL				12000000ul

/*==============================================================================
 Static function prototypes
==============================================================================*/
static void flash_latency(uint32_t frequency);
static void pll0_feed(void);
static void pll0Config(void);
static void system_init(void);
/*==============================================================================
 Global function prototypes
==============================================================================*/

/*==============================================================================
 Global function definitions
==============================================================================*/
/*------------------------------------------------------------------------------
 function name:
 description:
 parameters:
 returned value:
------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
 function name:   systemInit
 description:     this function initialize the following modules:
                   - PLL
                   - MAM
                   - fast I/O
                   - interrupt vector
                   - set maximum speed for peripherals
 parameters:      system frequency
 returned value:  none
------------------------------------------------------------------------------*/
void systemInit (void)
{
   system_init();
   flash_latency(SYSTEM_FREQUENCY);
   pll0Config();
}
/*==============================================================================
 Static function definitions
==============================================================================*/
/*------------------------------------------------------------------------*//**
* \brief Configures Flash latency
* \details Configures Flash latency (wait-states) which allows the chip to run
* at higher speeds
*
* \param [in] frequency defines the target frequency of the core
*//*-------------------------------------------------------------------------*/

static void flash_latency(uint32_t frequency)
{
	uint32_t wait_states;

	wait_states = frequency / 20000000;		// 1 CLK per 20MHz

	if (wait_states > 5)					// 5 CLKs is the highest reasonable value, works for up to 120MHz
		wait_states = 5;

	LPC_SC->FLASHCFG = ((wait_states - 1) << LPC_SC_FLASHCFG_FLASHTIM_bit) | LPC_SC_FLASHCFG_RESERVED_value;	// set the latency
}

/*------------------------------------------------------------------------*//**
* \brief PLL0 feed sequence
* \details Issues a special "PLL0 feed sequence" which validates the changes to
* PLL0 control registers
*//*-------------------------------------------------------------------------*/

static void pll0_feed(void)
{
	LPC_SC->PLL0FEED = LPC_SC_PLL0FEED_FIRST;
	LPC_SC->PLL0FEED = LPC_SC_PLL0FEED_SECOND;
}

/*------------------------------------------------------------------------*//**
* \brief Starts the PLL0
* \details Configure and enable PLL0 to achieve some frequency with some
* crystal. Before the speed change Flash latency is configured via
* flash_latency(). PLL0 parameters prediv and mul and core clock divider are
* based on both function parameters. The PLL0 is set up, enabled and connected.
*
* \param [in] crystal is the frequency of the crystal resonator connected to the
* LPC1769
* \param [in] frequency is the desired target frequency after enabling the PLL0
*
* \return real frequency that was set
*//*-------------------------------------------------------------------------*/

static void pll0Config(void)
{
	uint32 MValue, PValue;

	MValue = 9;
	PValue = 0;

	/* 1. make sure the PLL output is not already being used */
	LPC_SC->CLKSRCSEL = LPC_SC_CLKSRCSEL_CLKSRC_RC;		/* set internal RC as clock source */
	LPC_SC->PLL0CON		= 0;							/* disable PLL0 */
	pll0_feed();
	LPC_SC->SCS |= (1 << 5);							/* enable main oscillator */
	while(((LPC_SC->SCS & (1 << 6)) == 0));				/* wait for main oscillator to start up */

	/* 2. write the correct value to the CLKSRCSEL */
	LPC_SC->CLKSRCSEL = LPC_SC_CLKSRCSEL_CLKSRC_MAIN;	/* set main oscillator as PLL0 clock source */

	/* 3. write PLL new setup values to PLLCFG & enable PLL */
	LPC_SC->PLL0CFG = (MValue << 0) | (PValue << 5);
	pll0_feed();
	LPC_SC->PLL0CON = 1;
	pll0_feed();

	/* 4. set up clock dividers */
	LPC_SC->CCLKSEL = (1 << 0);

	/* 5. wait for PLL to lock */
	while( ((LPC_SC->PLL0STAT & (1 << 10)) == 0) );

	LPC_SC->CCLKSEL |= (1 << 8);			// connect PLL0 as clock source
	pll0_feed();
}

/*------------------------------------------------------------------------*//**
* \brief Initializes system
* \details Changes all PCLKs to 1:1 with core
*//*-------------------------------------------------------------------------*/

static void system_init(void)
{
	LPC_SC->PCLKSEL = 1;
# if 0
			LPC_SC_PCLKSEL0_PCLK_WDT_DIV1 |LPC_SC_PCLKSEL0_PCLK_TIMER0_DIV1 |
			LPC_SC_PCLKSEL0_PCLK_TIMER1_DIV1 | LPC_SC_PCLKSEL0_PCLK_UART0_DIV1 |
			LPC_SC_PCLKSEL0_PCLK_UART1_DIV1 | LPC_SC_PCLKSEL0_PCLK_PWM1_DIV1 |
			LPC_SC_PCLKSEL0_PCLK_I2C0_DIV1 | LPC_SC_PCLKSEL0_PCLK_SPI_DIV1 |
			LPC_SC_PCLKSEL0_PCLK_SSP1_DIV1 | LPC_SC_PCLKSEL0_PCLK_DAC_DIV1 |
			LPC_SC_PCLKSEL0_PCLK_ADC_DIV1 | LPC_SC_PCLKSEL0_PCLK_CAN1_DIV1 |
			LPC_SC_PCLKSEL0_PCLK_CAN2_DIV1 | LPC_SC_PCLKSEL0_PCLK_ACF_DIV1;
	LPC_SC->PCLKSEL1 = LPC_SC_PCLKSEL1_PCLK_QEI_DIV1 | LPC_SC_PCLKSEL1_PCLK_GPIOINT_DIV1 |
			LPC_SC_PCLKSEL1_PCLK_PCB_DIV1 | LPC_SC_PCLKSEL1_PCLK_I2C1_DIV1 |
			LPC_SC_PCLKSEL1_PCLK_SSP0_DIV1 | LPC_SC_PCLKSEL1_PCLK_TIMER2_DIV1 |
			LPC_SC_PCLKSEL1_PCLK_TIMER3_DIV1 | LPC_SC_PCLKSEL1_PCLK_UART2_DIV1 |
			LPC_SC_PCLKSEL1_PCLK_UART3_DIV1 | LPC_SC_PCLKSEL1_PCLK_I2C2_DIV1 |
			LPC_SC_PCLKSEL1_PCLK_I2S_DIV1 | LPC_SC_PCLKSEL1_PCLK_RIT_DIV1 |
			LPC_SC_PCLKSEL1_PCLK_SYSCON_DIV1 | LPC_SC_PCLKSEL1_PCLK_MC_DIV1;
# endif
}

/******************************************************************************
* END OF FILE
******************************************************************************/


